#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ucontext.h>
#include "threadStructure.h"
#include "fifoThread.h"

/*
 * create an element from a thread
 */

element * createElement(thread *thr){
  element * elm = (element *)malloc(sizeof(element));
  if(elm){
    elm->th = thr;
    elm->next = NULL;
    elm->previous = NULL;
    return elm;
  }
  return NULL;  
}

/*
 *
 */
thread* findThreadByTid (fifoThread * f,int tid){
  if(!f)
    return NULL;
  element *elm = f->head;
  while(elm){
    if(elm->th->tid == tid){ 
      return elm->th;
    }
    elm = elm->next;
  }  
  return NULL;
}

/*
 *
 */

void removeElement(fifoThread * f, element* elm){
  if(elm->previous)
    elm->previous->next = elm->next;
  else
    f->head = elm->next;
  if(elm->next)
    elm->next->previous = elm->previous;
  else{
    if(elm->previous)
      elm->previous->next = NULL;
    f->tail = elm->previous;
  }
}

thread* removeThreadByTid (fifoThread * f, int tid){
  assert(f);
  element *elm = f->head;
  while(elm){
    if(elm->th->tid == tid){
      removeElement(f,elm);
      thread * th = elm->th; 
      free(elm);
      return th;
    }
    elm = elm->next;
  }  
  return NULL;
}

/*
 *
 */

thread* removeBigPriority (fifoThread * f){
  assert(f);
  if(f->head == NULL)
    return NULL;
  element *elm = f->head;
  element *bigPriority = elm;
  while(elm){
    int p1 = elm->th->priority.priorite_actu; 
    int p2 = bigPriority->th->priority.priorite_actu;
    if(p1 > p2){
      bigPriority = elm;
    }
    elm = elm->next;
  }
  removeElement(f,bigPriority);
  thread* th = bigPriority->th;
  free(bigPriority);
  return th;
}
/*
 * create the fifo thread
*/
fifoThread * createFifoThread(){
  fifoThread* f = (fifoThread *)malloc(sizeof(fifoThread));
  if(f){
    f->head = NULL;
    f->tail = NULL;
    return f;
  }
  return NULL;
}

/*
 *
 */
int isEmptyFifo (fifoThread *fifo){
  assert(fifo);
  if(fifo->head)
    return 0;
  return 1;
}

/*
 * init a fifo thread
 */
void initFifoThread(fifoThread * fifo){
  assert(fifo);
  element *elm = fifo->head;
  while(elm){
    element * tmp = elm;
    elm = elm->next;
    free(tmp->th->context->uc_stack.ss_sp);
    free(tmp->th->context->uc_link);
    free(tmp->th->context);
    free(tmp->th);
    free(tmp);
  }
}

/*
 * kill a fifo thread
 */

void killFifoThread(fifoThread * fifo){
  initFifoThread(fifo);
  free(fifo);
}

/*
 * add an element to the fifo thread
 */

void addFifoThread(fifoThread *fifo, thread *th){
  assert(fifo && th);
  element * elm = createElement(th);
  if(fifo->head){
    element * tmp = fifo->tail;
    tmp->next = elm;
    elm->previous = tmp;
    fifo->tail = elm;
  }
  else{
    fifo->head = elm;
    fifo->tail = elm;
  }
}

/*
 * return the thread which is at the head of fifo thread
 */

struct thread* getFifoHead (fifoThread* fifo){
  assert(fifo->head);
  return fifo->head->th;
}

/*
 * remove the thread which is at the head of fifo thread
 */

struct thread* removeFifoHead (fifoThread* fifo){
  assert(fifo->head);
  element * tmp = fifo->head;
  thread* th = tmp->th;
  if(hasMoreThanOneElement(fifo)){
    fifo->head = fifo->head->next;
    fifo->head->previous = NULL;    
  }
  else{
    fifo->head = NULL;       
    fifo->tail = NULL;
  }    
  free(tmp);
  return th;
}

/*
 *
 */
int hasMoreThanOneElement(fifoThread* fifo){
  assert(fifo);
  if(fifo->head && fifo->head->next)
    return 1;
  return 0;
}

/*
 *
 */
void killThreadChildrenFromFIFO(int tid,fifoThread *f){
  element *elm = f->head;
  while(elm){
    if(elm->th->father && (elm->th->father->tid == tid)){
      removeElement(f,elm);
      thread * th = elm->th; 
      element* tmp = elm;
      if(th->is_father == TRUE){
	killThreadChildrenFromFIFO(th->tid, f);
      }
      free(th->context->uc_stack.ss_sp);
      free(th->context);
      free(th);
      elm = tmp->next;
      free(tmp);
      continue;
    }
    elm = elm->next;
  }  
}
 
